【セッションレポート】AWS コンテナサービスから考える安全なアプリケーションデリバリー(AWS-34) #AWSSummit
こんにちは。
モダンアプリコンサル部の坂本です。
前回に引き続き、今回はAWS Summit Japan 2024で参加した、 AWS コンテナサービスから考える安全なアプリケーションデリバリー のレポートを書いていこうと思います。
登壇者、セッション概要
登壇者
落水 恭介
アマゾン ウェブ サービス ジャパン合同会社 サービス&テクノロジー事業統括本部 エンタープライズアプリケーションソリューション本部 コンテナスペシャリストソリューションアーキテクト
セッション概要
プロダクトの新規リリースや機能追加が高速化している現代において、アプリケーションのデプロイが頻繁に行われることは珍しくありません。その一方で、デプロイの頻度を落とすことなく、プロダクトの価値をデリバリーするためには、デプロイが安全なものでなければいけません。本セッションでは、AWS コンテナサービスを例に、どのように安全なデプロイのプロセスを構築しアプリケーションをデリバリーしていくのか、いくつかのパターンをご紹介します。
セッションレポート
安全なアプリケーションデリバリー
機能追加や変更に際して、開発チームは入念に試験や動作確認を行うが、バグや予期しないエラーなどは発生してしまう。
デリバリー前の工程を手厚く実施したとしても、完全に障害を排除することは困難。
しかし、障害が発生した際の影響を小さくすることはできる。
今回は 障害などの意図しない状況が発生した場合の影響を最小限にできること を安全なアプリケーションデリバリーと定義する。
どうアプローチするか?
新機能を段階的に公開し、新機能を利用するユーザーを絞れば新機能のデリバリーによる障害の影響を受けるユーザー少なくできるはず。
であれば新機能を段階的に公開する方法をデリバリーのプロセスに持たせれば良い。
この方法を実現するために、以下のような手法がある。
- 線形デプロイ / Canaryデプロイ
トラフィックの一部を新バージョンに向ける - 機能フラグ(Feature Flag)
ユーザーのリクエストに含まれる属性に応じて新バージョンに機能を有効にして処理を行う
線形デプロイ / Canaryデプロイ
アプリケーションの前段にトラフィックをコントロールするコンポーネント(ロードバランサーなど)を配置し、一部のトラフィックのみを新バージョンに向ける方法。
例えばトラフィックの10%を新バージョンに向け、徐々に新バージョンへのトラフィックを増やしていく。
最終的に全トラフィックが新バージョンに向けばデプロイを完了とする。
線形デプロイ、Canaryデプロイ共に上記の基本的な手法は共通しているが、トラフィックの移行パターンに違いがある。
- 線形デプロイ
新バージョンへのトラフィックを線形に増やしていく
0% -> 10% -> 20% -> 30% -> ... -> 100% - Canaryデプロイ
少ないトラフィックで確認できたら、残りは一括で新バージョンに向ける
0% -> 10% -> 100%
慎重さを重視したい場合は線形デプロイ、スピード感が欲しい場合にCanaryデプロイを選択するなどで使い分けすると良い。
これら二つのデプロイ構成をAmazon ECSで実現する場合、以下の要素が必要となる。
- ELB
- トラフィックの分散に使用
- ALBでは加重ターゲットグループの重み比率によって振り分けされる
- 同一ユーザーがバージョンを跨がないようにスティッキーセッションで振り分けの維持をすることができる
- Amazon ECS
新旧バージョンのアプリケーションを稼働させる - AWS CodeDeploy
新旧バージョンのタスクを起動・停止したり、トラフィックの比率のコントロールする司令塔
線形 / Canaryデプロイではアプリケーションの改修が不要。
機能フラグ(Feature Flag)
アプリケーションのコードを書き換えることなくアプリケーションの振る舞いを変える方法。
アプリケーションコード内で機能フラグのON/OFFによって処理の実行する/しないを切り替えるようにしておく。
あらかじめアプリケーションコード内にフラグ判定を持たせる必要はある。
機能フラグは外部に持ち、アプリケーションからは外部の機能フラグを参照するようにする。
線形 / Canaryデプロイと異なり、アプリケーションのデプロイは直接現環境に行ってしまう。
ただし、この際機能フラグはOFFにすることによって、新機能を閉じた状態にしておく。
例として、
- 機能フラグそのものと、機能フラグがONの場合に機能を開放するユーザーのID群を外部に切り出し、これを新機能の実行条件としてアプリケーションで分岐させる
- この状態で本番環境へのデプロイを実行し、機能フラグをOFF、ユーザーID群を空の状態にしておく
- 機能フラグをONにしつつ、機能を開放するユーザーID群を全ユーザーの10%程度指定する
- 新機能は全ユーザーの約10%にのみ開放される
機能フラグをAmazon ECSで実現する場合、以下の要素が必要となる。
- AWS AppConfig
機能フラグの保存と配布 - Amazon ECS
- アプリケーションの稼働
- AWS AppConfigのエージェント(AppConfigエージェント)の稼働
AppConfigエージェントはAWS AppConfigが提供するConfignの定期取得を実行するコンテナ
キャッシュやポーリング間隔などの調整も可能
アプリケーションコンテナはAppConfigエージェントのコンテナに対し、機能フラグをHttpリクエストで取得するだけで良くなり、シンプルな構造にすることができる
機能フラグはリリースフラグ、実験フラグなど他にも様々なユースケースで使用できる。
アプリケーション側の条件式次第で、様々なユースケース、公開範囲に対応できる。
自動ロールバック
デプロイに問題が発生した場合、ロールバックを実行する必要が出てくるが、昨今はCI/CDのパイプラインの構築によって自動化が推進されている傾向にある。
そのため、問題発生した際のロールバックも自動化しなければ、運用者がデプロイ期間中に張り付かなければいけなくなってしまう。
デプロイの自動化にはロールバックの自動化も重要になってくる。
ただし、ロールバックの自動化を行うには、バージョンアップの前後で破壊的な変更を行わないようにする必要がある。
例えばバージョンアップ前後で読み書きするファイルの形式が異なるなどがあると、ロールバックしたとしても新バージョンで書き込みされたファイルを旧バージョンで読み取れないのでデータの不整合が発生する。
これに対するアプローチとして、2フェーズデプロイがある。
- 2フェーズデプロイ
1まとまりの変更に対し、デプロイを2フェーズで分けることで、破壊的変更を含まないようにする手法。
例えば上記のファイル形式の変更の例だと、新形式のファイルの読み取りのみを先にリリースし、その後新しいファイル形式の書き込みをリリースする。
こうすることによって、仮に新形式のファイルの書き込みでの障害が発生してロールバックしたとしても、新形式のファイルの読み取りは先にリリースされているのでデータの不整合が発生しなくなる。
Amazon ECSでの自動ロールバックを構成するにはどちらもAmazon CloudWatchを利用する。
- 線形デプロイ / Canaryデプロイ
- Amazon CloudWatchとAWS CodeDeployを連携させることで、CloudWatch アラームがALARM状態になった時に自動でロールバック
- 機能フラグ
- Amazon CloudWatchとAWS AppConfigを連携させることで、CloudWatch アラームがALARM状態になった時に自動でロールバック
まとめ
意図しない障害などの発生を防ぐことは困難だが、影響範囲の最小化、素早く切り戻す構成を取ることで軽減はできる。
そのためには以下のようアプローチが検討できる。
- 線形デプロイ / Canaryデプロイ
- 機能フラグ
- 自動ロールバック
上記のデプロイのアプローチを行うためにはそれぞれ、AWSでは以下の要素が必要。
- 線形デプロイ / Canaryデプロイ
AWS CodeDeploy、Amazon CloudWatch - 機能フラグ
AWS AppConfig、Amazon CloudWatch
最後に
リリースは開発者にとって不安な要素ですし、いつまでも緊張の瞬間だと思います。
しかし、本セッションで登場したような手法を取り入れることによって、不安を低減し、アジリティ高くリリースすることができるのではないかと思います。
AWSではデプロイの手法からロールバックまでを包括的に管理できるようサービスを組み合わせることができるので、アプリケーションの特性やユースケースに応じて適切な手法を取り入れることで、リリースにおける心理的障壁や消耗を軽減できると思いました。